<template>
  <div id="ue4Viewer" ref="ue4ViewerRef">
    <div id="ue4Loading" class="text-center pt-300">
      <img class="loadingImg" src="@assets/imgs/loading.gif" />
      <div id="msgDiv" style="color: white">正在拼命渲染，请稍后...</div>
    </div>
    <div id="player" class="vw-100 vh-100"></div>
  </div>
</template>

<script>
const config = require("../../config");

export default {
  name: "ue4View",
  data() {
    return {
      /** 服务地址 */
      serverHost: "",
      /** 服务名称 */
      ue4name: "",
      /**UE4内容 */
      ueRender: "",
      /**UE4是否渲染完毕 */
      ueRendered: false,
      /**结构树 */
      treeData: [],
      replaceFields: { children: "child", title: "name", key: "id" },
      selectNodes: [],
      // 选中节点
      selectedKeys: [],
      // 展开节点
      expandedKeys: [],
      // 选中节点及子阶段ue4Id
      selectKeys: [],
      // 处理方法
      selectedNodeByue4Id: null,
      // 高亮样式
      highStyle: {
        borderColor: "#014562", //边框颜色RGBA，A表示透明度
        borderLight: 200, //发光强度，范围是1-255
        borderThickness: 1, //边框厚度
        fillColor: "#01456000" //填充颜色RGBA，无填充则透明度A为0
      },
      //标签点击事件列表
      labelClickEvents: [],
      //常规点击事件
      customEvents: []
    };
  },
  props: {
    // /**结构树是否展示 */
    // showTree: {
    //   type: Boolean,
    //   default: false,
    // },
    /**模型是否可以点击 */
    pickabled: {
      type: Boolean,
      default: false
    }
  },
  mounted() {
    this.initLoad(() => {
      this.$emit("onloaded");
    });
  },
  methods: {
    // =============================**UE4**======================================
    //
    initConfig() {
      //1.请求负载均衡服务获取推流地址
      let serverHost = "";
      let ue4name = "";
      if (process.env.NODE_ENV == "production") {
        serverHost = config.build.ue4host + ":" + config.build.ue4port;
        ue4name = config.build.ue4name;
      } else {
        serverHost = config.dev.ue4host + ":" + config.dev.ue4port;
        ue4name = config.dev.ue4name;
      }
      this.serverHost = serverHost;
      this.ue4name = ue4name;
    },

    //初始化加载内容
    initLoad(callback) {
      let that = this;

      //ue4服务名称
      if (!this.ue4name) {
        this.initConfig();
      }

      //1.请求负载均衡服务获取推流地址
      let serverHost = this.serverHost;
      let ue4name = this.ue4name;

      console.log("serverHost", serverHost);
      let ueRender = new UERender({
        elementId: "player",
        serverHost: serverHost, //推流服务地址
        // serverHost: '127.0.0.1:8888', //推流服务地址
        // ue4name: 'hello', //ue4名称
        ue4name: ue4name, //ue4名称
        print_inputs: false, //控制台日志开关
        pick_mouse: 0, //pick操作的触发鼠标键，0-左键，1-中建 2-右键
        onLoadStateChange: function(s) {
          //加载状态
          if (s === LoadStateType.Waiting) {
            document.getElementById("msgDiv").innerHTML = "正在请求渲染资源...";
          } else if (s === LoadStateType.Connecting) {
            document.getElementById("msgDiv").innerHTML =
              "连接渲染服务成功，正在加载场景...";
          } else if (s === LoadStateType.Connected) {
            document.getElementById("msgDiv").innerHTML =
              "场景加载成功，即将进入渲染世界...";
            that.ueRendered = true;
          }
        },
        onLoadComplete: () => {
          //加载完成后隐藏loading
          document.getElementById("ue4Loading").style.display = "none";
          //忽略对地板的拾取
          that.pickignore();
          //拾取逻辑开启
          that.pickUe4Handle();
          if (callback && typeof callback === "function") {
            callback();
          }

          //设置旋转角度
          that.cameraRange();
          // //设置默认天气为晴天
          // that.changeWeather("2");
        },
        //添加标签点击事件
        onLabelClick: function(e) {
          // e.id 标签ID
          // e.type  0:点击标签本地（默认） 1:点击标签某个部分，需要UE4处理
          console.log("标签点击：", e);
          //
          let funs = that.labelClickEvents;
          if (funs && Array.isArray(funs)) {
            for (let i = 0; i < funs.length; i++) {
              const fun = funs[i];
              if (typeof fun === "function") {
                fun(e);
              }
            }
          }
        },
        //自定义的事件
        onCustomData: function(e) {
          console.log("收到UE自定义数据：", e);
          let funs = that.customEvents;
          if (funs && Array.isArray(funs)) {
            for (let i = 0; i < funs.length; i++) {
              const fun = funs[i];
              if (typeof fun === "function") {
                fun(e);
              }
            }
          }
        }
      });
      //开启推流
      ueRender.startPlay();
      that.ueRender = ueRender;
    },

    /**
     * 切换服务
     */
    changeUe4name(key) {
      let that = this;
      if (that.ue4name === key) {
        return;
      }
      if (that.ueRender) {
        that.ueRender.close();
        that.ueRender = null;
      }

      this.ue4name = key;
      this.initLoad();
    },

    //添加custom事件
    addCustomEvent(fun) {
      if (typeof fun === "function") {
        this.customEvents.push(fun);
      }
    },
    //添加label点击事件
    addLabelEvent(fun) {
      if (typeof fun === "function") {
        this.labelClickEvents.push(fun);
      }
    },
    setSelectedNodeByue4Id(callback) {
      this.selectedNodeByue4Id = callback;
    },

    // 树结构节点点击触发
    selectNodeHeightLight(selectKeys) {
      console.log("当前选中的树节点：", selectKeys);
      // 去除高亮
      this.unhighlightAll();
      this.selectNodes = selectKeys || [];
      this.highlight(this.selectNodes);
    },

    flyto(node, p) {
      //pitch俯仰角，yaw旋转角
      let that = this;
      let ueRender = this.ueRender;
      that.preInfo = null;
      if (
        node &&
        node.ue4Location &&
        (node.ue4Yaw || node.ue4Yaw == 0) &&
        (node.ue4Pitch || node.ue4Pitch == 0)
      ) {
        that.preInfo = {
          location: JSON.parse(node.ue4Location),
          pitch: node.ue4Pitch,
          yaw: node.ue4Yaw
        };
      } else {
        if (p && p.id) {
          let p2 = { id: p.id, duration: 0.1 };
          if (p) {
            p2 = Object.assign(p2, p);
          }
          // //聚焦
          ueRender.call(FUNC_CODE.Camera.focus, p2);
          return;
        }
        if (node.hasChild === "0" && node.ue4Id) {
          let p2 = { id: node.ue4Id, duration: 0.1 };
          if (p) {
            p2 = Object.assign(p2, p);
          }
          // //聚焦
          ueRender.call(FUNC_CODE.Camera.focus, p);
          return;
        }
      }
      let param = that.preInfo;
      // 默认参数
      if (!param) {
        // that.$message.warning('未设置坐标属性！')
        return;
        // param = {
        //   location: { x: 10000, y: 10000, z: 10000 },
        //   pitch: -40,
        //   yaw: 0,
        //
      }
      this.flytoByParam(param);
    },
    //聚焦
    focus(ue4Id, distance) {
      let ueRender = this.ueRender;
      let param = Object.assign({ duration: 0.1 }, param);
      //param.speed = 500;
      ueRender.call(FUNC_CODE.Camera.focus, {
        id: ue4Id,
        distance: distance || 5000
      });
    },
    //转换视角到某个坐标
    flytoByParam(param, duration) {
      let ueRender = this.ueRender;
      param = Object.assign(
        { duration: duration == undefined ? 2 : duration },
        param
      );
      //param.speed = 500;
      ueRender.call(FUNC_CODE.Camera.flyto, param);
    },

    //忽略对地板的点击拾取
    pickignore() {
      let ueRender = this.ueRender;

      var ids = [];
      //土地
      for (let index = 1; index <= 5; index++) {
        const element = index;
        ids.push("S_DX_0" + index);
      }
      //水体
      ids.push("S_SYSM_001");
      ids.push("S_XYSM_001");
      ids.push("S_XYSM_002");
      //流体
      for (let index = 1; index <= 26; index++) {
        if (index < 10) {
          ids.push("BP_FluxModifierSourceActor" + index);
        } else {
          ids.push("BP_FluxModifierSourceActor0" + index);
        }
      }
      ids.push("BPFluxSimulation");
      ids.push("EUA_FluxSimulationEditor");
      ids.push("BP_FluxSurface_Ocean_2");
      ids.push("BP_FluxSimulation_2");
      ids.push("NODE_AddChildActorComponent-2_BP_FluxSurface_Default_C_CAT_16");

      //空气墙
      ids.push("BlockingVolume_1");

      ueRender.call(FUNC_CODE.Object.addPickIgnore, { ids: ids });
    },

    //添加拾取监听
    pickUe4Handle() {
      let that = this;
      let ueRender = this.ueRender;
      //开启UE4场景拾取开关
      ueRender.pickable = true;
      ueRender.onPick = e => {
        // console.log("pick", e);
        this.$emit("pick", e);
        if (that.pickabled) {
          // 实现点击物体高亮
          if (e["object"] && typeof that.selectedNodeByue4Id === "function") {
            // 反选树节点
            let node = that.selectedNodeByue4Id(e["object"].id, e);
            if (node && node.id) {
              // 高亮
              that.selectNodeHeightLight([node.ue4Id]);
              // 飞入模型位置
              that.flyto(node);
            }
          }
        }
      };
    },

    PickSwitch() {
      let that = this;
      let ueRender = that.ueRender;
      let highId = that.highId;
      ueRender.pickable = !ueRender.pickable;
      if (ueRender.pickable) {
        console.log("拾取开");
      } else {
        console.log("拾取关");
      }
    },

    /**获取物体坐标 */
    get(ue4id, callback) {
      let ueRender = this.ueRender;
      //高亮
      ueRender.call(FUNC_CODE.Object.get, ue4id, callback);
    },

    /**高亮 */
    highlight(selectNodes, isHighlight) {
      if (!selectNodes || selectNodes.length == 0) {
        return;
      }
      let ueRender = this.ueRender;
      let _isHighlight = true;
      if (isHighlight === false) {
        _isHighlight = false;
      }
      let ids = selectNodes;
      //高亮
      for (let index = 0; index < ids.length; index++) {
        const id = ids[index];
        let param = {
          id: id, //对象ID
          isHighlight: _isHighlight, //是否高亮
          style: this.highStyle
        };
        ueRender.call(FUNC_CODE.Object.highlight, param);
      }
    },

    /**新增、更新标签 */
    addUpdateLabel(p) {
      let ueRender = this.ueRender;
      // let p = {
      //   type: "mark",
      //   scale: 1,
      //   offset: { x: 0, y: 0 },
      //   clickable: true,
      //   config: [
      //     {
      //       id: "mark1",
      //       title: "标签#1",
      //       objectid: "S_ZSMC_24",
      //       value: "9999",
      //       valueColor: "#ff0000cc",
      //     },
      //     {
      //       id: "mark2",
      //       title: "标签#2",
      //       objectid: "S_JSKZBQ_03",
      //       value: "2222",
      //       icon: "mark1",
      //     },
      //     {
      //       id: "mark3",
      //       title: "标签#3",
      //       objectid: "S_LWS_08",
      //       //valueColor:'#000000ee',
      //       //value:'88888',
      //       icon: "mark3",
      //       //iconUrl:''
      //     },
      //   ],
      // };
      ueRender.call(FUNC_CODE.ScreenLable.addOrUpdate, p);
    },
    // 场景重置操作
    reset(homeView) {
      // 清除所有高亮
      this.unhighlightAll();

      //隐藏所有的mark点
      this.removeAllMark();

      // //视角回到原点
      // this.flytoHomeView(homeView);
    },
    /**
     * 设置镜头的移动范围和旋转范围
     */
    cameraRange(location, pitch) {
      let ueRender = this.ueRender;
      let p = {};
      if (!pitch) {
        pitch = [-90, 90];
      }
      // {
      //   location: [
      //     { x: 10000, y: 10000, z: 10000 },
      //     { x: -10000, y: -10000, z: -100 }
      //   ],
      //   pitch: [-90, 90]
      // }
      p.pitch = pitch;
      if (location) p.location = location;
      ueRender.call(FUNC_CODE.Camera.setRange, p);
    },
    // 去除所有高亮
    unhighlightAll() {
      let ueRender = this.ueRender;
      let param = {
        id: "*", //对象ID
        isHighlight: false //是否高亮
      };
      ueRender.call(FUNC_CODE.Object.highlight, param);
    },
    // 去除所有标签
    removeAllMark(id) {
      let ueRender = this.ueRender;
      ueRender.call(FUNC_CODE.ScreenLable.remove, id ? id : "*");
    },
    //显示、隐藏所有标签
    showHideMark(id, isHidden, isLike) {
      let ueRender = this.ueRender;
      let funcode = FUNC_CODE.ScreenLable.show;
      if (isHidden) {
        funcode = FUNC_CODE.ScreenLable.hide;
      }
      if (isLike) {
        id = id + "*";
      }
      ueRender.call(funcode, id);
    },
    // 去除所有高亮
    flytoHomeView(homeView) {
      let ueRender = this.ueRender;
      let param = {
        location: {
          x: -3817.118408203125,
          y: -12043.8486328125,
          z: 4593.34912109375
        },
        pitch: -4.999998569488525,
        yaw: 90.00011444091797
      };
      if (homeView) {
        param = Object.assign(param, homeView);
      }
      this.flytoByParam(param);
    },
    //控制旋转
    objectRotateTo(ue4id, target, duration) {
      let ueRender = this.ueRender;
      ueRender.call(FUNC_CODE.Object.rotate, {
        id: ue4id,
        duration: duration == undefined ? 5 : duration,
        target: target
      });
    },
    //控制旋转
    objectRotate(ue4id, vector, duration) {
      let ueRender = this.ueRender;
      ueRender.call(FUNC_CODE.Object.rotate, {
        id: ue4id,
        duration: duration == undefined ? 5 : duration,
        // target: target,
        vector: vector
      });
    },
    //控制移动
    objectMove(ue4id, vector, duration) {
      let ueRender = this.ueRender;
      ueRender.call(FUNC_CODE.Object.move, {
        id: ue4id,
        // target: target,
        duration: duration == undefined ? 5 : duration,
        vector: vector // { x: -4854.373047, y: -908.71991, z: 4820.233398 },
      });
    },
    objectMoveTo(ue4id, target, duration) {
      let ueRender = this.ueRender;
      ueRender.call(FUNC_CODE.Object.move, {
        id: ue4id,
        target: target,
        duration: duration == undefined ? 5 : duration
      });
    },
    //显示隐藏
    show(ue4id) {
      let ueRender = this.ueRender;
      let ids = [];
      if (Array.isArray(ue4id)) {
        ids = ue4id;
      } else {
        ids = [ue4id];
      }
      ueRender.call(FUNC_CODE.Object.show, { ids: ids });
    },
    hide(ue4id) {
      let ueRender = this.ueRender;
      let ids = [];
      if (Array.isArray(ue4id)) {
        ids = ue4id;
      } else {
        ids = [ue4id];
      }
      ueRender.call(FUNC_CODE.Object.hide, { ids: ids });
    },
    //控制水流
    waterControl(ids, styleParam) {
      let ueRender = this.ueRender;
      let param = {
        ids: ids,
        runTime: 5, //运行时间，从当前值到目标值的持续时间
        zoffset: 100,
        style: styleParam
      };
      //单独调用自定义接口
      ueRender.custom("WaterControl", param);
    },
    //水轮发电机组仿真
    sljSimulation(typecode, opened) {
      let ueRender = this.ueRender;
      let param = {
        type: typecode ? typecode : 0, //整数，0：全局模式（全部开启和全局视角） 1：1号机组，2：2号机组，3：3号机组，4：4号机组
        state: opened ? 1 : 0, //开关状态   1：开启 0：关闭
        mode: 1 //仿真模式，1：按照要求的动画进行仿真，0：无动画，立即就位到对应状态。
      };

      //单独调用自定义接口
      ueRender.custom("SLJSimulation", param);
    },
    //控制水流并控制泄水闸转动
    waterRotateControl(param) {
      let ueRender = this.ueRender;
      //单独调用自定义接口
      ueRender.custom("WaterRotateControl", param);
    },
    //第一人称
    firstPerson(location, pitch, yaw) {
      let ueRender = this.ueRender;
      let p = {
        speed: 100
      };
      if (location) {
        p.location = location;
      }
      if (yaw || yaw == 0) {
        p.yaw = yaw;
      }
      if (pitch || pitch == 0) {
        p.pitch = pitch;
      }
      ueRender.call(FUNC_CODE.Camera.firstPerson, p);
      //{"location":{"x":-3697.099854,"y":722.984924,"z":4736.741211},"speed":100}
    },
    //第三人称
    thirdPerson(location, pitch, yaw) {
      let ueRender = this.ueRender;
      let p = {
        speed: 100
      };
      if (location) {
        p.location = location;
      }
      if (yaw || yaw == 0) {
        p.yaw = yaw;
      }
      if (pitch || pitch == 0) {
        p.pitch = pitch;
      }
      ueRender.call(FUNC_CODE.Camera.thirdPerson, p);
    },
    //自动巡检
    autoXunjian(lineid, points, duration) {
      let ueRender = this.ueRender;
      let param = {
        lineid: lineid,
        duration: duration == undefined ? 5 : duration,
        points: points
      };
      ueRender.custom("Xunjian", param);
    },
    //光照参数获取
    getLight(code, callback) {
      let ueRender = this.ueRender;
      let p = {
        id: code
      };
      ueRender.custom("getLight", callback || callback());
    },
    //光照参数设置
    setLight(code, param) {
      let ueRender = this.ueRender;
      let p = {
        id: code,
        intensity: param.intensity
      };
      ueRender.custom("setLight", p);
    },
    //控制天气
    changeWeather(type, times) {
      let ueRender = this.ueRender;
      //{"type":"2","daynight":"night"}
      let param = {
        type: type,
        times: 960
      };
      if (times != null && times != undefined) {
        param.times = times;
      }
      console.log("ChangeWeather", JSON.stringify(param));
      //单独调用自定义接口
      ueRender.custom("ChangeWeather", param);
    },
    //水面设置
    waterStyle(param) {
      let ueRender = this.ueRender;
      let p = {
        tagname: param.tagname || "water"
      };
      p = Object.assign(p, param);
      // let data = {
      //   tagname: "water",
      //   waterColourLight: "#ffffff",
      //   waterColourDark: "#ffffff",
      //   waveNormalSpeed: -5,
      //   waveSpeed: 10,
      //   normalLargeIntensity: 4,
      //   normalMedIntensity: 0.05,
      //   normalSmallIntensity: 4,
      //   opacity: 1,
      // };
      ueRender.custom("WaterStyle", p);
    },
    //水面设置
    waterStyle(param) {
      let ueRender = this.ueRender;
      let p = {
        tagname: param.tagname || "water"
      };
      p = Object.assign(p, param);
      // let data = {
      //   tagname: "water",
      //   waterColourLight: "#ffffff",
      //   waterColourDark: "#ffffff",
      //   waveNormalSpeed: -5,
      //   waveSpeed: 10,
      //   normalLargeIntensity: 4,
      //   normalMedIntensity: 0.05,
      //   normalSmallIntensity: 4,
      //   opacity: 1,
      // };
      ueRender.custom("WaterStyle", p);
    },
    //水轮发电机组转动
    waterTurbineRotate(ids, isRotate) {
      let ueRender = this.ueRender;
      if (isRotate === undefined) {
        isRotate = true;
      }
      ueRender.custom("WaterTurbineRotate", {
        ids: ids, //水轮机叶片ID
        speed: 9, //旋转速度
        rotate: isRotate //是否旋转，true开始旋转，false关闭旋转
      });
    },
    combineFunc() {
      let param = {
        ids: ["S_HXGZM_19", "S_HXGZM_20"],
        runTime: 5, //运行时间，从当前值到目标值的持续时间
        zoffset: 0,
        style: {
          volume: 5,
          speedX: 0,
          speedY: 2,
          edge: 10,
          intensity: 1,
          duration: -1
        }
      };
      //单独调用自定义接口
      //ueRender.custom('WaterControll',param);

      //调用组合接口
      let params = [
        {
          code: FUNC_CODE.Custom,
          data: { code: "WaterControll", data: param }
        },
        {
          code: FUNC_CODE.Object.highlight,
          data: { id: "S_HXGZM_19", isHighlight: true }
        },
        {
          code: FUNC_CODE.Object.highlight,
          data: { id: "S_HXGZM_20", isHighlight: true }
        },
        {
          code: FUNC_CODE.Object.rotate,
          data: { id: "S_HXGZM_19", vector: { roll: 60 }, duration: 5 }
        },
        {
          code: FUNC_CODE.Object.rotate,
          data: { id: "S_HXGZM_20", vector: { roll: 60 }, duration: 5 }
        }
      ];
      ueRender.callMulti(params, e => {
        console.log(e);
      });
    }
  },
  created() {
    // this.loadData();
  },
  beforeDestroy() {
    let that = this;
    if (that.ueRender) {
      that.ueRender.close();
      that.ueRender = null;
    }
  }
};
</script>

import 'ant-design-vue/dist/antd.less';
<style lang="less">
#ue4Viewer {
  width: 100%;
  height: 100%;

  #ue4Loading {
    z-index: 99;
    top: 0%;
    left: 0%;
    width: 100%;
    height: 100%;
    position: absolute;
    // background-color: #fff;
    text-align: center;

    .loadingImg {
      margin-top: 300px;
    }
  }

  #player {
    width: 100%;
    // height: calc(100% - 5px);
    height: 100%;
    background-color: #000;
    overflow: hidden;

    #streamingVideo {
      width: 100%;
      height: 100%;
      vertical-align: top;
    }
  }

  .layout-container {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    overflow: hidden;
    // background: url(../assets/imgs/bg.png) no-repeat;
    // background-size: 100% 100%;
    pointer-events: none;
    box-shadow: inset 0px 0px 150px 150px rgba(34, 55, 80, 1);
  }
}
</style>
